#pragma once

#include "Port.h"

#include "Interface.h"
#include "ProtocolStateMachine.h"

namespace uml {

const bool Port::isBehavior_default_ = false;
const bool Port::isConjugated_default_ = false;
const bool Port::isService_default_ = true;
Port::Port(const QString& umlType)
    : Property(umlType) {}

void Port::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    Property::fromJson(json, errorList);
    isBehavior_ = json.value("isBehavior").toBool(isBehavior_default_);
    isConjugated_ = json.value("isConjugated").toBool(isConjugated_default_);
    isService_ = json.value("isService").toBool(isService_default_);
    protocol_ = JsonSerializable::create<ProtocolStateMachine>(json.value("protocol"), errorList);

    JsonSerializable::fromJsonArray(provided_, "provided", json, errorList);
    JsonSerializable::fromJsonArray(redefinedPorts_, "redefinedPorts", json, errorList);
    JsonSerializable::fromJsonArray(required_, "required", json, errorList);
}

void Port::toJson(QJsonObject& json) {
    Property::toJson(json);
    if (isBehavior_ != isBehavior_default_) {
        json.insert("isBehavior", isBehavior_);
    }
    if (isConjugated_ != isConjugated_default_) {
        json.insert("isConjugated", isConjugated_);
    }
    if (isService_ != isService_default_) {
        json.insert("isService", isService_);
    }
    if (protocol_) {
        QJsonObject protocol_json;
        protocol_->toJson(protocol_json);
        json.insert("protocol", protocol_json);
    }
    JsonSerializable::toJsonArray(provided_, "provided", json);
    JsonSerializable::toJsonArray(redefinedPorts_, "redefinedPorts", json);
    JsonSerializable::toJsonArray(required_, "required", json);
}

/// <summary>
/// basicProvided
    /// The union of the sets of Interfaces realized by the type of the Port and its
    /// supertypes, or directly the type of the Port if the Port is typed by an
    /// Interface.
/// </summary>
    /// <code>
    /// result = (if type.oclIsKindOf(Interface) 
    /// then type.oclAsType(Interface)->asSet() 
    /// else type.oclAsType(Classifier).allRealizedInterfaces() 
    /// endif)
    /// </code>
shared_ptr<vector<Interface>> Port::basicProvided() const
{
    return nullptr;
}

/// <summary>
/// basicRequired
    /// The union of the sets of Interfaces used by the type of the Port and its
    /// supertypes.
/// </summary>
    /// <code>
    /// result = ( type.oclAsType(Classifier).allUsedInterfaces() )
    /// </code>
shared_ptr<vector<Interface>> Port::basicRequired() const
{
    return nullptr;
}

/// <summary>
/// isBehavior getter
/// Specifies whether requests arriving at this Port are sent to the classifier
/// behavior of this EncapsulatedClassifier. Such a Port is referred to as a
/// behavior Port. Any invocation of a BehavioralFeature targeted at a behavior Port
/// will be handled by the instance of the owning EncapsulatedClassifier itself,
/// rather than by any instances that it may contain.
/// </summary>
bool Port::isBehavior() const {
    return isBehavior_;
}

/// <summary>
/// isBehavior setter
/// Specifies whether requests arriving at this Port are sent to the classifier
/// behavior of this EncapsulatedClassifier. Such a Port is referred to as a
/// behavior Port. Any invocation of a BehavioralFeature targeted at a behavior Port
/// will be handled by the instance of the owning EncapsulatedClassifier itself,
/// rather than by any instances that it may contain.
/// </summary>
void Port::setIsBehavior(bool value) {
    isBehavior_ = value;
}

/// <summary>
/// isConjugated getter
/// Specifies the way that the provided and required Interfaces are derived from the
/// Port’s Type.
/// </summary>
bool Port::isConjugated() const {
    return isConjugated_;
}

/// <summary>
/// isConjugated setter
/// Specifies the way that the provided and required Interfaces are derived from the
/// Port’s Type.
/// </summary>
void Port::setIsConjugated(bool value) {
    isConjugated_ = value;
}

/// <summary>
/// isService getter
/// If true, indicates that this Port is used to provide the published functionality
/// of an EncapsulatedClassifier.  If false, this Port is used to implement the
/// EncapsulatedClassifier but is not part of the essential externally-visible
/// functionality of the EncapsulatedClassifier and can, therefore, be altered or
/// deleted along with the internal implementation of the EncapsulatedClassifier and
/// other properties that are considered part of its implementation.
/// </summary>
bool Port::isService() const {
    return isService_;
}

/// <summary>
/// isService setter
/// If true, indicates that this Port is used to provide the published functionality
/// of an EncapsulatedClassifier.  If false, this Port is used to implement the
/// EncapsulatedClassifier but is not part of the essential externally-visible
/// functionality of the EncapsulatedClassifier and can, therefore, be altered or
/// deleted along with the internal implementation of the EncapsulatedClassifier and
/// other properties that are considered part of its implementation.
/// </summary>
void Port::setIsService(bool value) {
    isService_ = value;
}

/// <summary>
/// protocol getter
/// An optional ProtocolStateMachine which describes valid interactions at this
/// interaction point.
/// </summary>
shared_ptr<ProtocolStateMachine> Port::protocol() const {
    return protocol_;
}

/// <summary>
/// protocol setter
/// An optional ProtocolStateMachine which describes valid interactions at this
/// interaction point.
/// </summary>
void Port::setProtocol(shared_ptr<ProtocolStateMachine> value) {
    protocol_ = value;
}

/// <summary>
/// provided getter
/// The Interfaces specifying the set of Operations and Receptions that the
/// EncapsulatedCclassifier offers to its environment via this Port, and which it
/// will handle either directly or by forwarding it to a part of its internal
/// structure. This association is derived according to the value of isConjugated.
/// If isConjugated is false, provided is derived as the union of the sets of
/// Interfaces realized by the type of the port and its supertypes, or directly from
/// the type of the Port if the Port is typed by an Interface. If isConjugated is
/// true, it is derived as the union of the sets of Interfaces used by the type of
/// the Port and its supertypes.
/// </summary>
vector<shared_ptr<Interface>>& Port::provided() {
    return provided_;
}

/// <summary>
/// redefinedPorts getter
/// A Port may be redefined when its containing EncapsulatedClassifier is
/// specialized. The redefining Port may have additional Interfaces to those that
/// are associated with the redefined Port or it may replace an Interface by one of
/// its subtypes.
/// </summary>
vector<shared_ptr<Port>>& Port::redefinedPorts() {
    return redefinedPorts_;
}

/// <summary>
/// required getter
/// The Interfaces specifying the set of Operations and Receptions that the
/// EncapsulatedCassifier expects its environment to handle via this port. This
/// association is derived according to the value of isConjugated. If isConjugated
/// is false, required is derived as the union of the sets of Interfaces used by the
/// type of the Port and its supertypes. If isConjugated is true, it is derived as
/// the union of the sets of Interfaces realized by the type of the Port and its
/// supertypes, or directly from the type of the Port if the Port is typed by an
/// Interface.
/// </summary>
vector<shared_ptr<Interface>>& Port::required() {
    return required_;
}

} // namespace uml
